﻿/*************************************************************************
 * Created by OhZee Creative, LLC
 * 2013
 * This code is licensed under Microsoft Public License (Ms-PL)
 * http://opensource.org/licenses/ms-pl
 * http://ozframework.codeplex.com/
 *************************************************************************/

namespace OhZeeCreative.Helpers
{
	using System;
	using System.Collections.Generic;
	using System.Diagnostics;

#if SILVERLIGHT
    using System.Windows;
    using System.Windows.Media.Animation;
#endif
#if NETFX_CORE
	using Windows.Foundation;
	using Windows.UI.Xaml.Media.Animation;
#endif

    public static class RadialHelper
	{
		public static Point GetRadialCoordinateForDegrees(double startAngle, double endAngle, double startRadius, double endRadius, double normalizedValue, EasingFunctionBase easing = null)
		{
			return GetRadialCoordinate(MathHelper.Radians(startAngle), MathHelper.Radians(endAngle), startRadius, endRadius, normalizedValue, easing);
		}

		public static Point GetRadialCoordinate(double startAngle, double endAngle, double startRadius, double endRadius, double normalizedValue, EasingFunctionBase easing = null)
		{
			double ease = easing == null ? normalizedValue : easing.Ease(normalizedValue);
			double radius = MathHelper.ActualValue(startRadius, endRadius, ease);

            //double angle = MathHelper.ActualValue(startAngle, endAngle, ease);
            double angle = MathHelper.ActualValue(startAngle, endAngle, normalizedValue); // Not using easing here to be consistent with GetRadialCoordinates()

			return GetRadialCoordinate(angle, radius);
		}

		public static Point GetRadialCoordinate(double angle, double radius)
		{
#if SILVERLIGHT
            Point point = new Point();
#endif
#if NETFX_CORE
            Point point;
#endif
			point.X = radius * Math.Cos(angle);
			point.Y = -radius * Math.Sin(angle); // In Math coordinates, Y grows upwards, in drawing coordinates, Y grows downwards.

			return point;
		}

		public static Point[] GetRadialCoordinatesForDegrees(double startAngle, double endAngle, double startRadius, double endRadius, int numberOfPoints, EasingFunctionBase easing = null, bool equalDeltasForAll = false)
		{
			return GetRadialCoordinates(MathHelper.Radians(startAngle), MathHelper.Radians(endAngle), startRadius, endRadius, numberOfPoints, easing, equalDeltasForAll);
		}

		public static Point[] GetRadialCoordinates(
			double startAngle, double endAngle, 
			double startRadius, double endRadius, 
			int numberOfPoints, 
			EasingFunctionBase easing = null, 
			bool equalDeltasForAll = false)
		{
			if (numberOfPoints < 2)
			{
				DebugHelper.Fail();
				return new Point[0];
			}

			Point[] points = new Point[numberOfPoints];

			int numberOfDeltas = equalDeltasForAll ? numberOfPoints : numberOfPoints - 1;

			double deltaRadius = MathHelper.DeltaValue(startRadius, endRadius, numberOfDeltas);
			double deltaAngle = MathHelper.DeltaValue(startAngle, endAngle, numberOfDeltas);

			for (int index = 0; index < numberOfPoints; index++)
			{
				double percentage = MathHelper.NormalValue(0, numberOfPoints - 1, index);

				double radius;
				if (easing != null)
				{
					double ease = easing.Ease(percentage);
					radius = MathHelper.ActualValue(startRadius, endRadius, ease);
				}
				else // Linear
				{
					radius = startRadius + index * deltaRadius;
				}

                // ATTENTION: Not using easing here (by design?) - similarly in GetRadialCoordinate()
				double angle = startAngle + index * deltaAngle;

				// In Math coordinates, Y grows upwards, in drawing coordinates, Y grows downwards.
				points[index] = GetRadialCoordinate(angle, radius);
			}

			return points;
		}

		public static double[] GetDistances(Point offset, Point[] locations)
		{
			double[] distances = new double[locations.Length];
			for (int i = 0; i < locations.Length; i++)
			{
				distances[i] = MathHelper.Hypotenuse(locations[i].X - offset.X, locations[i].Y - offset.Y);
			}

			return distances;
		}

		public static Point OffsetPoint(this Point origin, Point offset)
		{
			Point point = origin;
			point.X += offset.X;
			point.Y += offset.Y;
			return point;
		}
	}
}
